﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataTransferObject;
using System.Data;
using System.Text.RegularExpressions;
using DataTransferObject.DiaryAndTrackingTask.SupportClassForDiary;

namespace Engine
{
   
    /// <summary>
    /// Chứa dữ liệu các vị trí từ khóa được parse:
    /// Tên từ khóa + vị trí xuất hiện=> tại sao không build đầy đủ keywordRegex+ValueRegex?
    /// Danh sách value của những giá trị đi kèm với từ khóa đó. vd: duration value.
    /// </summary>
    //private class KeywordParsed
    //{

    //}

    public class _2NLPAlgorithm : NLPAlgorithm
    {
        #region Constant
        public static String KEYWORD_INDEX = "Keyword Index";
        public static String KEYWORD_POSIT = "Keyword Position";
        public static String KEYWORD_VALUE = "Keyword Value";
        private static int NO_SPLIT = -999;
        private static int DEFAULT_SPLIT = 5;
        private const String SPLITCHARACTER = "usedùngthiscáinàyuniqueduynhấtonetođểsplitwordcắttừ";

        #endregion

        #region Attributes
        private List<String> catchedValue = new List<String>(); // list chứa những chuỗi chắc chắn không có trong task name; lấy được từ các thông số khác
        private Boolean isTask = true;//Nếu nó chỉ có name -> Nó sẽ là Task

        private List<String> durationKeyword = new List<String>();
        private List<String> deadlineKeyword = new List<String>();
        private List<String> minsplitKeyword = new List<String>();
        private List<String> priorityKeyword = new List<String>();

        private List<int> durationKeyWordPos = new List<int>();
        private List<int> deadlineKeywordPos = new List<int>();


        private DataTable durationDTB = new DataTable();
        private DataTable deadlineDTB = new DataTable();
        private DataTable priorityDTB = new DataTable();
        private List<priorityTable> pri = new List<priorityTable>();
        //các từ như: buổi sáng, buổi chiều, sáng, chiều...
        private List<String> timeOfDay = new List<String>();
        /// <summary>
        /// các từ như: ngày mai, mốt, tuần sau, tháng sau, tháng tới...
        /// </summary>
        private List<String> daytimeIndex = new List<String>();
        // ví dụ: tuần này, tuần sau, tuần kia
        private List<String> weektimeIndex = new List<string>();
        //ví dụ: tháng này, tháng tới...
        private List<String> monthtimeIndex = new List<string>();
        //vi du: thu hai, thu ba, thu 4
        private List<String> dayOfWeek = new List<string>();
        //ví dụ: tháng 1, tháng 2
        private List<String> monthOfYear = new List<string>();

        private List<String> deadlineHourKeyword = new List<String>();
        private List<String> durationHourKeyword = new List<String>();
        private List<String> minuteKeyword = new List<String>();
        private List<String> secondKeyword = new List<String>();
        private List<String> symbolKeyword = new List<String>();
        private List<String> eventStartKeyword = new List<String>();

        // chuoi dùng test :D
        String tempInput;
        
        private String durationKWPattern = @"(?<durationKW>";
        private String deadlineKWPattern = @"(?<deadlineKW>";
        private String minsplitKWPattern = @"(?<minsplitKW>";
        private String eventStartKWPattern = @"(?<eventStartKW>";

        private String priorityKWPattern = @"(?<priorityKW>";
        private NameValue priorityNV = new NameValue();

        private String timeOfDayPattern = @"(?<moment>";
        private String daytimeIndexPattern = @"(?<daytimeIndex>";
        private NameValue daytimeIndexNV = new NameValue();
        private String weektimeIndexPattern = @"(?<weektimeIndex>";
        private NameValue weektimeIndexNV = new NameValue();
        private String monthtimeIndexPattern = @"(\s*(ngày|ngay)\s*(?<dayInMonth>(\d+))\s*)?(?<monthtimeIndex>";
        private NameValue monthtimeIndexNV = new NameValue();
        private String dayOfWeekPattern = @"(?<dayOfWeek>";
        private NameValue dayOfWeekNV = new NameValue();
        private String monthOfYearPattern = @"(\s*(?<dayInMonthOfYear>(\d{1,2}))?\s*)(?<monthOfYear>";
        private NameValue monthOfYearNV = new NameValue();

        private String hourPattern = @"(?<hour>";
        private String minutePattern = @"(?<minute>";
        private String secondPattern = @"(?<second>";
        private String datePattern = @"(?<date>";
        private String timePattern = @"(?<time>";
        private String symbolPattern = @"(?<symbol>";
        private String minsplitPattern = @"(?<minsplit>";
        private String durationPattern = @"(?<duration>";
        private String deadlinePattern = @"(?<deadline>";
        private String eventStartPattern = @"(?<eventStart>";
        private String priorityPattern = @"(?<priority>";

        private List<String> durationValue = new List<String>();
        private List<String> deadlineValue = new List<String>();
        private List<String> minsplitValue = new List<String>();
        private List<String> priorityValue = new List<String>();
        private List<String> eventStartValue = new List<String>();
        private List<String> dateValue = new List<String>();
        private List<String> timeValue = new List<String>();
        private List<String> timeOfDayValue = new List<String>();
        private List<String> dayTimeIndexValue = new List<String>();
        private List<String> dayOfWeekValue = new List<String>();
        private List<String> weekTimeIndexValue = new List<String>();
        private List<String> monthTimeIndexValue = new List<String>();
        private List<String> monthOfYearValue = new List<String>();
        private List<int> keyWordPosition = new List<int>();

        MatchCollection durationMC;
        MatchCollection deadlineMC;
        MatchCollection eventStartMC;
        MatchCollection minsplitMC;
        MatchCollection priorityMC;
        MatchCollection timeMC;
        MatchCollection dateMC;
        MatchCollection timeOfDayMC;
        MatchCollection dayTimeIndexMC;
        MatchCollection dayOfWeekMC;
        MatchCollection weekTimeIndexMC;
        MatchCollection monthTimeIndexMC;
        MatchCollection monthOfYearMC;
        /// <summary>
        /// đánh dấu Match Duration được chọn bởi Heuristic. Sau khi dùng Index này chúng ta 
        /// sẽ lấy được Match Duration từ tập Matches Duration và dùng Group để lấy các giá trị trên nhóm này
        /// mà không cần phải viết lại Regex khác.
        /// </summary>
        private int selectedDurationMC = 0;
        private int selectedDeadlineMC = 0;
        private int selectedMinsplitMC = 0;
        private int selectedPriorityMC = 0;
        private int selectedEventStartMC = 0;
        #endregion

        #region constructors

        /// <summary>
        /// Tạo danh sách keywords và cấu trúc dữ liệu để xử lý (datatable)
        /// </summary>
        /// <param name="_taskInputTxt"></param>
        public _2NLPAlgorithm(String _taskInputTxt)
        {
            initiateKeyword();
            initiateRegex();
            initiateDataTable();
            _taskResult = new Task();
            _eventResult = new JskeEvent();
            this._taskInputTxt = _taskInputTxt.ToLower();
            this._originalInputTxt = _taskInputTxt;
        }
        #endregion

        #region initialize

        private void initiateKeyword()
        {
            initDurationKW();

            initDeadlineKW();

            initMinsplitKW();

            initEventStartKW();

            initTimeOfDayKW();

            initDayOfWeekKW();

            initMonthOfYearKW();

            initDayTimeIndexKW();

            initWeektimeIndexKW();

            initMonthtimeIndexKW();

            initHourMiniteSecondKW();

            initSymbolKW();

            initPriorityKW();
        }

        private void initiateDataTableColumn(DataTable dtb)
        {
            dtb.Columns.Add(KEYWORD_INDEX, typeof(int));
            dtb.Columns.Add(KEYWORD_POSIT, typeof(List<int>));
            dtb.Columns.Add(KEYWORD_VALUE, typeof(List<String>));
        }

        private void initiateRegex()
        {
            buildRegexPattern(ref durationKWPattern, durationKeyword);
            buildRegexPattern(ref deadlineKWPattern, deadlineKeyword);
            buildRegexPattern(ref minsplitKWPattern, minsplitKeyword);
            buildRegexPattern(ref priorityKWPattern, priorityKeyword);
            buildRegexPattern(ref hourPattern, deadlineHourKeyword);
            buildRegexPattern(ref minutePattern, minuteKeyword);
            buildRegexPattern(ref secondPattern, secondKeyword);
            buildRegexPattern(ref priorityPattern, priorityKeyword);
            buildRegexPattern(ref timeOfDayPattern, timeOfDay);
            buildRegexPattern(ref symbolPattern, symbolKeyword);

            buildRegexPattern(ref daytimeIndexPattern, daytimeIndex);
            buildRegexPattern(ref weektimeIndexPattern, weektimeIndex);
            buildRegexPattern(ref monthtimeIndexPattern, monthtimeIndex);
            buildRegexPattern(ref dayOfWeekPattern, dayOfWeek);
            buildRegexPattern(ref monthOfYearPattern, monthOfYear);
            buildRegexPattern(ref eventStartKWPattern, eventStartKeyword);
            monthOfYearPattern += @"(\s*(?<dayInMonthOfYearL>((\d{4})|(\d{1,2})))?\s*)";
            
            datePattern += @"(\d{4})|(\s*(ngày|ngay)?\s*\d{1,2}\s*(tháng|thang|/|\\|-)\s*\d{1,2}\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2}))|(\s*(tháng|thang|/|\\|-)?\s*\d{1,2}\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2}))|(\s*(ngày|ngay)?\s*\d{1,2}\s*(tháng|thang|/|\\|-)\s*\d{1,2}\s*)|(\s*(ngày|ngay)?\s*\d{1,2}\s*)|(\s*(tháng|thang|/|\\|-)\s*\d{1,2}\s*)|(\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2}))|(\d{4})"        
                +")";

            String unskipMinute = @"(((\d+/\d+)|(\d+(\.\d+)?))" + @hourPattern + ")?"
                + @"(((\d+/\d+)|(\d+(\.\d+)?))" + "(" + @minutePattern + ")" + ")"
                //+ @"(((\d+/\d+)|(\d+(\.\d+)?))" + @secondPattern + @")?"
                ;

            String unskipSecond = @"(((\d+/\d+)|(\d+(\.\d+)?))" + @hourPattern + ")?"
                + @"(((\d+/\d+)|(\d+(\.\d+)?))" + "(" + @minutePattern + ")" + ")?"
                //+ @"(((\d+/\d+)|(\d+(\.\d+)?))" + @secondPattern + @")"
                ;
            //có thể bắt dưới dạng: 3h15 -> phút có thể không cần đơn vị
            String unskipHour = @"(((\d+/\d+)|(\d+(\.\d+)?))" + @hourPattern + ")"
                + @"(((\d+/\d+)|(\d+(\.\d+)?))" + "(" + @minutePattern + ")?" + ")?"
                //+ @"(((\d+/\d+)|(\d+(\.\d+)?))" + @secondPattern + @")?"
                ;

            String durationValuePattern = "(?<durationValue>(" + unskipHour + "|" + unskipMinute 
                //+ "|" + unskipSecond 
                + "))";
            timePattern += "(" + unskipHour + "|" + unskipMinute 
                //+ "|" + unskipSecond 
                + "))";
            //timePattern += @"(((\d{1}|\d{2})" + @hourPattern + @"))?(\s)*((d{1}|d{2})" + @minutePattern + @"))(\s)*((d{1}|d{2})" + @secondPattern + ")))";
            //khoảng 4h30m
            durationPattern += "(" + @durationKWPattern + ")" + @"((\s*|$)" + @symbolPattern + @"(\s*|$))*" + @durationValuePattern + @")(,|.)?" + @"($|\s)";

            minsplitPattern += "("
                + @minsplitKWPattern
                + "(" + @symbolPattern + ")?"
                + @durationValuePattern
                + ")"
                + ")";

            //trước 4h sáng 20/10/2010
            //deadlinePattern += "("+@deadlineKWPattern +")?" + "(" + @durationValuePattern + ")?" + "(" + timeOfDayPattern + ")?" + "(" + datePattern + ")?)";
            //String superDeadlineValue = "(" 
            //    + "(" + @durationValuePattern + ")?|"
            //    + "(" + timeOfDayPattern + ")?|"
            //    + "(" + daytimeIndexPattern + ")?|"
            //    + "(" + dayOfWeekPattern + ")?|"
            //    + "(" + weektimeIndexPattern + ")?|"
            //    + "(" + monthtimeIndexPattern + ")?|"
            //    + "(" + monthOfYearPattern + ")?|"
            //    + "(" + datePattern + ")?"
            //    +")*";

            deadlinePattern += "(" + @deadlineKWPattern + ")+" 
                + @"((\s*|$)" + @symbolPattern + @"(\s*|$))*"
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")?"
                + ")";

            String unskipDurationVal = @"("
                + "(" + @durationValuePattern + ")"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")?"
                + ")";
            String unskipDatePattern = @"("
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")"
                + ")";
            String unskipDayTimeIndexPattern = @"("
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")?"
                + ")";
            String unskipDayOfWeekPattern = @"("
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")?"
                + ")";
            String unskipWeekTimeIndexPattern = @"("
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")?"
                + ")";
            String unskipMonthTimeIndexPattern = @"("
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")"
                + "(" + monthOfYearPattern + ")?"
                + "(" + datePattern + ")?"
                + ")";
            String unskipMonthOfYearPattern = @"("
                + "(" + @durationValuePattern + ")?"
                + "(" + timeOfDayPattern + ")?"
                + "(" + daytimeIndexPattern + ")?"
                + "(" + dayOfWeekPattern + ")?"
                + "(" + weektimeIndexPattern + ")?"
                + "(" + monthtimeIndexPattern + ")?"
                + "(" + monthOfYearPattern + ")"
                + "(" + datePattern + ")?"
                + ")";
            eventStartPattern += "(" + eventStartKWPattern + ")" 
                + @"((\s*|$)" + @symbolPattern + @"(\s*|$))*"
                + "(" 
                + unskipDurationVal + "|"
                //+ timeOfDayPattern + "|"
                + unskipDayTimeIndexPattern + "|"
                + unskipDayOfWeekPattern + "|"
                + unskipWeekTimeIndexPattern + "|"
                + unskipMonthTimeIndexPattern + "|"
                + unskipMonthOfYearPattern + "|"
                + unskipDatePattern + "|"
                + ")"
                + ")";

            //deadlinePattern += "(" + @deadlineKWPattern + ")+" + @"((\s*|$)"
            //    + @symbolPattern + @"(\s*|$))*"
            //    + @superDeadlineValue
            //    + ")";

        }

        private void initiateDataTable()
        {
            initiateDataTableColumn(durationDTB);
            initiateDataTableColumn(deadlineDTB);
            initiateDataTableColumn(priorityDTB);
        }

        private void initDurationKW()
        {
            durationKeyword.Add("-");
            durationKeyword.Add(":");
            durationKeyword.Add("trong");
            durationKeyword.Add("in");
            durationKeyword.Add("khoảng");
            durationKeyword.Add("about");
            durationKeyword.Add("khoang");
            durationKeyword.Add("chắc khoảng");
            durationKeyword.Add("in about");
            durationKeyword.Add("chac khoang");
            durationKeyword.Add("trong khoảng");
            durationKeyword.Add("trong khoang");
            durationKeyword.Add("takes");
            durationKeyword.Add("took");
            durationKeyword.Add("take");
            durationKeyword.Add("mất");
            durationKeyword.Add("cost");
            durationKeyword.Add("mat");
            durationKeyword.Add("take about");
            durationKeyword.Add("takes about");
            durationKeyword.Add("cost about");
            durationKeyword.Add("mất khoảng");
            durationKeyword.Add("mat khoang");
            durationKeyword.Add("mất chừng");
            durationKeyword.Add("mat chung");
            durationKeyword.Add("hết");
            durationKeyword.Add("het");
            durationKeyword.Add("hết khoảng");
            durationKeyword.Add("het khoang");
            durationKeyword.Add("hết chừng");
            durationKeyword.Add("het chung");
            durationKeyword.Add("chừng");
            durationKeyword.Add("chung");
            durationKeyword.Add("cỡ");
            durationKeyword.Add("ước chừng");
            durationKeyword.Add("uoc chung");
            durationKeyword.Add("khoảng chừng");
            durationKeyword.Add("khoang chung");
            durationKeyword.Add("duration");
            durationKeyword.Add("last");
            durationKeyword.Add("for");
        }

        private void initDeadlineKW()
        {
            deadlineKeyword.Add("trước");
            deadlineKeyword.Add("phải xong trước");
            deadlineKeyword.Add("phải hoàn thành trước");
            deadlineKeyword.Add("nên xong trước");
            deadlineKeyword.Add("nên hoàn thành trước");

            deadlineKeyword.Add("dự kiến trước");
            deadlineKeyword.Add("dự kiến phải xong trước");
            deadlineKeyword.Add("dự kiến phải hoàn thành trước");
            deadlineKeyword.Add("dự kiến nên xong trước");
            deadlineKeyword.Add("dự kiến nên hoàn thành trước");

            deadlineKeyword.Add("before");

            deadlineKeyword.Add("complete before");
            deadlineKeyword.Add("should complete before");
            deadlineKeyword.Add("must complete before");

            deadlineKeyword.Add("complete before or after");
            deadlineKeyword.Add("should complete before or after");
            deadlineKeyword.Add("must complete before or after");

            deadlineKeyword.Add("must before or after");

            deadlineKeyword.Add("finish on or before");
            deadlineKeyword.Add("should finish on or before");
            deadlineKeyword.Add("must finish on or before");

            deadlineKeyword.Add("should finish on");
            deadlineKeyword.Add("must finish on");

            deadlineKeyword.Add("closing date");
            deadlineKeyword.Add("trc");
            deadlineKeyword.Add("truoc");
            deadlineKeyword.Add("hạn chót");
            deadlineKeyword.Add("duedate");
            deadlineKeyword.Add("han chot");
            deadlineKeyword.Add("hết hạn");
            deadlineKeyword.Add("het han");
            deadlineKeyword.Add("hạn");
            deadlineKeyword.Add("han");
            deadlineKeyword.Add("deadline");
        }

        private void initMinsplitKW()
        {
            minsplitKeyword.Add("tối thiểu");

            minsplitKeyword.Add("_không chia");
            minsplitKeyword.Add("_không chia nhỏ");
            minsplitKeyword.Add("_không split");
            minsplitKeyword.Add("_nosplit");
            minsplitKeyword.Add("_no split");
            minsplitKeyword.Add("_nonsplit");

            minsplitKeyword.Add("tối thiểu trong");
            minsplitKeyword.Add("tối thiểu cỡ");
            minsplitKeyword.Add("làm tối thiểu trong");
            minsplitKeyword.Add("làm ít nhất");
            minsplitKeyword.Add("minsplit");
            minsplitKeyword.Add("ít nhất");
            minsplitKeyword.Add("khoảng chia nhỏ nhất");
            minsplitKeyword.Add("minimum split");
            minsplitKeyword.Add("minimum time split");
        }

        private void initEventStartKW()
        {
            eventStartKeyword.Add("đúng");
            eventStartKeyword.Add("lúc");
            eventStartKeyword.Add("vào lúc");
            eventStartKeyword.Add("vào");
            eventStartKeyword.Add("sau");
            eventStartKeyword.Add("thông báo");
            eventStartKeyword.Add("thông báo trước");
            //eventStartKeyword.Add("cỡ");
        }

        private void initTimeOfDayKW()
        {
            timeOfDay.Add("am in the morning");
            timeOfDay.Add("in the morning");
            timeOfDay.Add("in the afternoon");
            timeOfDay.Add("in the evening");
            timeOfDay.Add("buổi sáng");
            timeOfDay.Add("morning");
            timeOfDay.Add("buoi sang");
            timeOfDay.Add("buổi trưa");
            timeOfDay.Add("afternoon");
            timeOfDay.Add("buoi trua");
            timeOfDay.Add("noon");
            timeOfDay.Add("buổi chiều");
            timeOfDay.Add("buoi chieu");
            timeOfDay.Add("evening");
            timeOfDay.Add("buổi tối");
            timeOfDay.Add("buoi toi");
            timeOfDay.Add("sáng");
            timeOfDay.Add("trưa");

            timeOfDay.Add("chiều");
            timeOfDay.Add("tối");
            timeOfDay.Add("khuya");
            timeOfDay.Add("night");
            timeOfDay.Add("midnight");
            timeOfDay.Add("sang");
            timeOfDay.Add("trua");
            timeOfDay.Add("chieu");
            timeOfDay.Add("toi");
            timeOfDay.Add("am");
            timeOfDay.Add("pm");

            //timeOfDay.Add("sáng mai");
            //timeOfDay.Add("sáng ngày mai");
            //timeOfDay.Add("tomorrow morning");

            //timeOfDay.Add("trưa mai");
            //timeOfDay.Add("tomorrow afternoon");
            //timeOfDay.Add("trưa ngày mai");

            //timeOfDay.Add("chiều mai");

            //timeOfDay.Add("tối mai");
            //timeOfDay.Add("tối ngày mai");
            //timeOfDay.Add("tomorrow evening");

            //timeOfDay.Add("sáng mốt");
            //timeOfDay.Add("the day after tomorrow morning");
            //timeOfDay.Add("sáng ngày mốt");

            //timeOfDay.Add("trưa mốt");
            //timeOfDay.Add("the day after tomorrow afternoon");
            //timeOfDay.Add("trưa ngày mốt");

            //timeOfDay.Add("chiều mốt");

            //timeOfDay.Add("tối mốt");
            //timeOfDay.Add("tối ngày mốt");
            //timeOfDay.Add("the day after tomorrow evening");


            //timeOfDay.Add("trưa kia");
            //timeOfDay.Add("trưa ngày kia");

            //timeOfDay.Add("tối kia");
            //timeOfDay.Add("tối ngày kia");
        }

        private void initDayOfWeekKW()
        {
            //Chú ý không được tự ý thêm dữ liệu vào vì có thể gây parse dữ liệu keyword và value bị sai
            dayOfWeek.Add("thứ hai");
            dayOfWeek.Add("thứ 2");
            dayOfWeek.Add("monday");
            dayOfWeek.Add("mon");

            dayOfWeek.Add("thứ ba");
            dayOfWeek.Add("tuesday");
            dayOfWeek.Add("tue");
            dayOfWeek.Add("thứ 3");

            dayOfWeek.Add("thứ tư");
            dayOfWeek.Add("thứ 4");
            dayOfWeek.Add("wednesday");
            dayOfWeek.Add("wed");

            dayOfWeek.Add("thứ năm");
            dayOfWeek.Add("thứ 5");
            dayOfWeek.Add("thursday");
            dayOfWeek.Add("thu");

            dayOfWeek.Add("thứ sáu");
            dayOfWeek.Add("thứ 6");
            dayOfWeek.Add("friday");
            dayOfWeek.Add("fri");

            dayOfWeek.Add("thứ bảy");
            dayOfWeek.Add("thứ 7");
            dayOfWeek.Add("saturday");
            dayOfWeek.Add("sat");

            dayOfWeek.Add("chủ nhật");
            dayOfWeek.Add("cn");
            dayOfWeek.Add("saturday");
            dayOfWeek.Add("sat");
            double[] dayOfWeekVal = new double[] { 
                2, 2, 2, 2, 
                3, 3, 3, 3, 
                4, 4, 4, 4,
                5, 5, 5, 5,
                6, 6, 6, 6,
                7, 7, 7, 7,
                8, 8, 8, 8
            };

            mapNameValue(ref dayOfWeekNV, dayOfWeek, dayOfWeekVal);
        }

        private void initMonthOfYearKW()
        {
            monthOfYear.Add("tháng 1");
            monthOfYear.Add("tháng một");
            monthOfYear.Add("january");
            monthOfYear.Add("jan");

            monthOfYear.Add("tháng hai");
            monthOfYear.Add("tháng 2");
            monthOfYear.Add("february");
            monthOfYear.Add("feb");

            monthOfYear.Add("tháng ba");
            monthOfYear.Add("tháng 3");
            monthOfYear.Add("march");
            monthOfYear.Add("mar");

            monthOfYear.Add("tháng tư");
            monthOfYear.Add("tháng 4");
            monthOfYear.Add("april");
            monthOfYear.Add("apr");
            monthOfYear.Add("tháng bốn");

            monthOfYear.Add("tháng năm");
            monthOfYear.Add("tháng 5");
            monthOfYear.Add("may");

            monthOfYear.Add("tháng sáu");
            monthOfYear.Add("tháng 6");
            monthOfYear.Add("june");
            monthOfYear.Add("jun");

            monthOfYear.Add("tháng bảy");
            monthOfYear.Add("tháng 7");
            monthOfYear.Add("july");
            monthOfYear.Add("jul");

            monthOfYear.Add("tháng tám");
            monthOfYear.Add("tháng 8");
            monthOfYear.Add("august");
            monthOfYear.Add("aug");

            monthOfYear.Add("tháng chín");
            monthOfYear.Add("tháng 9");
            monthOfYear.Add("september");
            monthOfYear.Add("sep");

            monthOfYear.Add("tháng mười");
            monthOfYear.Add("tháng 10");
            monthOfYear.Add("october");
            monthOfYear.Add("oct");

            monthOfYear.Add("tháng mười một");
            monthOfYear.Add("tháng 11");
            monthOfYear.Add("november");
            monthOfYear.Add("nov");

            monthOfYear.Add("tháng mười hai");
            monthOfYear.Add("tháng 12");
            monthOfYear.Add("december");
            monthOfYear.Add("dec");

            double[] val = new double[] { 
                1, 1, 1, 1, 
                2, 2, 2, 2, 
                3, 3, 3, 3, 
                4, 4, 4, 4, 4, 
                5, 5, 5, 
                6, 6, 6, 6, 
                7, 7, 7, 7, 
                8, 8, 8, 8, 
                9, 9, 9, 9, 
                10, 10, 10, 10, 
                11, 11, 11, 11, 
                12, 12, 12, 12 };

            mapNameValue(ref monthOfYearNV, monthOfYear, val);
        }

        private void initDayTimeIndexKW()
        {
            daytimeIndex.Add("cuối hôm nay");
            daytimeIndex.Add("end of today");
            daytimeIndex.Add("ngày mai");
            daytimeIndex.Add("mai");
            daytimeIndex.Add("tomorrow");

            daytimeIndex.Add("sáng mai");
            daytimeIndex.Add("sáng ngày mai");
            daytimeIndex.Add("tomorrow morning");

            daytimeIndex.Add("trưa mai");
            daytimeIndex.Add("trưa ngày mai");
            daytimeIndex.Add("tomorrow afternoon");

            daytimeIndex.Add("chiều mai");

            daytimeIndex.Add("tối mai");
            daytimeIndex.Add("tối ngày mai");
            daytimeIndex.Add("tomorrow evening");

            daytimeIndex.Add("cuối ngày mai");
            daytimeIndex.Add("end of tomorrow");
            daytimeIndex.Add("ngày mốt");
            daytimeIndex.Add("the day after tomorrow");

            daytimeIndex.Add("sáng mốt");
            daytimeIndex.Add("the day after tomorrow morning");
            daytimeIndex.Add("sáng ngày mốt");

            daytimeIndex.Add("trưa mốt");
            daytimeIndex.Add("the day after tomorrow afternoon");
            daytimeIndex.Add("trưa ngày mốt");

            daytimeIndex.Add("chiều mốt");

            daytimeIndex.Add("tối mốt");
            daytimeIndex.Add("the day after tomorrow evening");
            daytimeIndex.Add("tối ngày mốt");

            daytimeIndex.Add("sáng kia");
            daytimeIndex.Add("sáng ngày kia");

            daytimeIndex.Add("trưa kia");
            daytimeIndex.Add("trưa ngày kia");

            daytimeIndex.Add("tối kia");
            daytimeIndex.Add("tối ngày kia");

            daytimeIndex.Add("cuối ngày mốt");
            daytimeIndex.Add("end of the day after tomorrow");
            daytimeIndex.Add("ngày kia");

            daytimeIndex.Add("cuối ngày kia");
            daytimeIndex.Add("ngày kìa");

            daytimeIndex.Add("cuối ngày kìa");

            double[] val = new double[] {
                1, 1, 1, 1, 1, 
                (double)1.25, (double)1.25, (double)1.25, 
                (double)1.5, (double)1.5, (double)1.5, 
                (double)((1.0 +(double)13/24)), 
                (double)1.75, (double)1.75,  (double)1.75, 
                2, 2, 2, 2, 
                (double)2.25, (double)2.25, (double)2.25, 
                (double)2.5, (double)2.5, (double)2.5, 
                (double)((2.0 +(double)13/24)), 
                (double)2.75, (double)2.75, (double)2.75, 
                (double)3.25, (double)3.25, 
                (double)3.5, (double)3.5, 
                (double)3.75, (double)3.75, 
                3, 3, 3, 
                4, 4, 
                5 
            };

            mapNameValue(ref daytimeIndexNV, daytimeIndex, val);
        }

        private void initWeektimeIndexKW()
        {
            weektimeIndex.Add("cuối tuần này");
            weektimeIndex.Add("this weekend");
            weektimeIndex.Add("weekend");

            weektimeIndex.Add("tuần sau");
            weektimeIndex.Add("next week");

            weektimeIndex.Add("cuối tuần sau");// trước thứ 7 tuần sau
            weektimeIndex.Add("next weekend");

            weektimeIndex.Add("tuần tới");
            weektimeIndex.Add("cuối tuần tới");

            weektimeIndex.Add("tuần kế");

            weektimeIndex.Add("cuối tuần kế");

            weektimeIndex.Add("tuần kế tiếp");

            weektimeIndex.Add("cuối tuần kế tiếp");

            weektimeIndex.Add("tuần kia");
            weektimeIndex.Add("cuối tuần kia");

            double[] val = new double[] {
                (double)5/7, (double)5/7, (double)5/7,
                1, 1, 
                (double)12/7, (double)12/7,
                1, (double)12/7, 
                1, 
                1, (double)12/7, 
                (double)12/7, 
                2, (double)19/7 };

            mapNameValue(ref weektimeIndexNV, weektimeIndex, val);
        }

        private void initMonthtimeIndexKW()
        {
            monthtimeIndex.Add("cuối tháng này");
            monthtimeIndex.Add("the end of this month");
            monthtimeIndex.Add("end of this month");

            monthtimeIndex.Add("tháng sau");
            monthtimeIndex.Add("next month");

            monthtimeIndex.Add("cuối tháng sau");
            monthtimeIndex.Add("the end of next month");
            monthtimeIndex.Add("end of next month");

            monthtimeIndex.Add("tháng tới");
            monthtimeIndex.Add("cuối tháng tới");
            monthtimeIndex.Add("tháng kế");
            monthtimeIndex.Add("cuối tháng kế");
            monthtimeIndex.Add("tháng kế tiếp");
            monthtimeIndex.Add("cuối tháng kế tiếp");

            monthtimeIndex.Add("tháng kia");
            monthtimeIndex.Add("cuối tháng kia");

            double[] val = new double[] {
                1, 1, 1,
                1, 1,
                2, 2, 2,
                1, 2, 1, 2, 1, 2,
                2, 3
            };

            mapNameValue(ref monthtimeIndexNV, monthtimeIndex, val);
        }

        private void initHourMiniteSecondKW()
        {
            deadlineHourKeyword.Add("giờ");
            deadlineHourKeyword.Add("gio");
            deadlineHourKeyword.Add("tiếng");
            deadlineHourKeyword.Add("tieng");
            deadlineHourKeyword.Add("hour");
            deadlineHourKeyword.Add("hours");
            deadlineHourKeyword.Add("h");
            deadlineHourKeyword.Add("am");
            deadlineHourKeyword.Add("pm");
            deadlineHourKeyword.Add("g");
            deadlineHourKeyword.Add(":");

            durationHourKeyword.Add("giờ");
            durationHourKeyword.Add("gio");
            durationHourKeyword.Add("tiếng");
            durationHourKeyword.Add("tieng");
            durationHourKeyword.Add("hour");
            durationHourKeyword.Add("hours");
            durationHourKeyword.Add("h");
            durationHourKeyword.Add("am");
            durationHourKeyword.Add("pm");
            durationHourKeyword.Add("g");
            durationHourKeyword.Add(":");


            minuteKeyword.Add("phút");
            minuteKeyword.Add("phut");
            minuteKeyword.Add("minute");
            minuteKeyword.Add("minutes");
            minuteKeyword.Add("min");
            minuteKeyword.Add("m");
            minuteKeyword.Add("p");
            minuteKeyword.Add("pm");
            minuteKeyword.Add("am");
            minuteKeyword.Add("ph");
            minuteKeyword.Add("'");
            minuteKeyword.Add(":");

            secondKeyword.Add("giây");
            secondKeyword.Add("giay");
            secondKeyword.Add("second");
            secondKeyword.Add("seconds");
            secondKeyword.Add("sec");
            secondKeyword.Add("s");
            secondKeyword.Add("gi");
            secondKeyword.Add("''");
        }

        private void initSymbolKW()
        {
            symbolKeyword.Add(":");
            symbolKeyword.Add("-");
        }

        private void initPriorityKW()
        {
            //1
            priorityKeyword.Add("cực kỳ quan trọng");
            priorityKeyword.Add("quan trọng cực kỳ");
            priorityKeyword.Add("vô cùng quan trọng");
            priorityKeyword.Add("siêu quan trọng");
            priorityKeyword.Add("extremely important");
            //2
            priorityKeyword.Add("rất quan trọng");
            priorityKeyword.Add("quan trọng lắm");
            priorityKeyword.Add("very important");
            priorityKeyword.Add("very necessary");
            //3
            priorityKeyword.Add("important");
            priorityKeyword.Add("quan trọng");
            priorityKeyword.Add("quan trong");
            priorityKeyword.Add("cần thiết");
            priorityKeyword.Add("can thiet");
            priorityKeyword.Add("critical");
            priorityKeyword.Add("necessary");
            //4
            priorityKeyword.Add("tương đối quan trọng");
            priorityKeyword.Add("khá quan trọng");
            priorityKeyword.Add("kha quan trong");
            priorityKeyword.Add("quite important");
            //5
            priorityKeyword.Add("kém quan trọng");
            priorityKeyword.Add("kem quan trong");
            priorityKeyword.Add("less important");
            //6            
            priorityKeyword.Add("bình thường");
            priorityKeyword.Add("binh thuong");
            priorityKeyword.Add("normal");
            //7
            priorityKeyword.Add("không cần thiết");
            priorityKeyword.Add("khong can thiet");
            priorityKeyword.Add("not necessary");
            //10
            priorityKeyword.Add("không quan trọng");
            priorityKeyword.Add("khong quan trong");
            priorityKeyword.Add("ko quan trọng");
            priorityKeyword.Add("ko quan trong");
            priorityKeyword.Add("k quan trọng");
            priorityKeyword.Add("k quan trong");
            priorityKeyword.Add("unimportant");
            priorityKeyword.Add("not important");
            priorityKeyword.Add("uncritical");
            priorityKeyword.Add("not critical");

            double[] prioVal = new double[] {
                1, 1, 1, 1, 1,
                2, 2, 2, 2, 
                3, 3, 3, 3, 3, 3, 3, 
                4, 4, 4, 4, 
                5, 5, 5, 
                6, 6, 6, 
                7, 7, 7, 
                10, 10, 10, 10, 10, 10, 10, 10, 10, 10 };

            mapNameValue(ref priorityNV, priorityKeyword, prioVal);
        }

        #endregion

        #region overridden Methods
        public override Object run()
        {
            //recognizeKeyword();
            recognizeValue();
            //if (durationValue.Count > 1 || deadlineValue.Count > 1 || priorityValue.Count > 1)
            //heuristicEnhancement();
            //build keyWordPosition

            //buildKeywordPosition(durationValue[0], deadlineValue[0], priorityValue[0], _taskInputTxt);
            if (isTask)
            {
                if (deadlineValue.Count > 0)
                {
                    _taskResult.DueDate = parseDeadlineValue(deadlineValue[0]);
                }
                if (_taskResult.DueDate.Year == 9999)
                    _taskResult.DueDate = DateTime.MaxValue;
                if (durationValue.Count > 0)
                {
                    _taskResult.RemainTime = parseDurationValue(durationValue[0]);
                }
                if (priorityValue.Count > 0)
                {
                    _taskResult.Priority = (int)parsePriorityValue(priorityValue[0]);
                }
                int minsplit = parseMinSplitValue();
                _taskResult.MinimumTimeSplit = (minsplit < 0) ? (minsplit == NO_SPLIT ? _taskResult.RemainTime : DEFAULT_SPLIT) : (minsplit);

                //hàm parse task name mới - TLong
                _taskResult.Name = parseTaskName();
                //_taskResult.Name = parseTaskName(keyWordPosition, _taskInputTxt);

                return this._taskResult;
            }
            else
            {
                if (deadlineValue.Count > 0)
                {
                    _eventResult.EventStart = parseDeadlineValue(deadlineValue[0]);
                }
                if (_eventResult.EventStart.Year == 9999)
                    _eventResult.EventStart = DateTime.Now;
                if (durationValue.Count > 0)
                {
                    _eventResult.EventDuration = parseDurationValue(durationValue[0]);
                }
                if (priorityValue.Count > 0)
                {
                    _eventResult.EventPriority = (EventPriority)(parsePriorityValue(priorityValue[0]) / 2);
                }

                //hàm parse task name mới - TLong
                _eventResult.EventName = parseTaskName();
                //_taskResult.Name = parseTaskName(keyWordPosition, _taskInputTxt);

                return this._eventResult;
            }
        }

        protected override void recognizeKeyword()
        {
            buildKeywordTable(durationKeyword, _taskInputTxt, durationDTB);
            buildKeywordTable(deadlineKeyword, _taskInputTxt, deadlineDTB);
            buildKeywordTable(priorityKeyword, _taskInputTxt, priorityDTB);
        }

        protected override void recognizeValue()
        {
            Regex durationRegex = new Regex(this.durationPattern);
            Regex deadlineRegex = new Regex(this.deadlinePattern);
            Regex priorityRegex = new Regex(this.priorityPattern);
            Regex minsplitRegex = new Regex(this.minsplitPattern);
            Regex eventStartRegex = new Regex(this.eventStartPattern);
            Regex timeRegex = new Regex(this.timePattern);
            Regex dateRegex = new Regex(this.datePattern);

            this.durationMC = durationRegex.Matches(_taskInputTxt);
            this.deadlineMC = deadlineRegex.Matches(_taskInputTxt);
            this.priorityMC = priorityRegex.Matches(_taskInputTxt);
            this.minsplitMC = minsplitRegex.Matches(_taskInputTxt);
            this.eventStartMC = eventStartRegex.Matches(_taskInputTxt);

            sendMCVal2TaskVal(durationMC, ref durationValue);
            sendMCVal2TaskVal(deadlineMC, ref deadlineValue);
            sendMCVal2TaskVal(eventStartMC, ref eventStartValue);

            String tempInputTxt = _taskInputTxt;
            //if (durationValue.Count() != 0) tempInputTxt = tempInputTxt.Replace(durationValue[0],"");
            //if (deadlineValue.Count() != 0 ) tempInputTxt =  tempInputTxt.Replace(deadlineValue[0], "");
            //if (eventStartValue.Count != 0) tempInputTxt = tempInputTxt.Replace(eventStartValue[0], "");

            Regex timeOfDayRegex = new Regex(timeOfDayPattern);
            Regex dayTimeIndexRegex = new Regex(daytimeIndexPattern);
            Regex dayOfWeekRegex = new Regex(dayOfWeekPattern);
            Regex weekTimeIndexRegex = new Regex(weektimeIndexPattern);
            Regex monthTimeIndexRegex = new Regex(monthtimeIndexPattern);
            Regex monthOfYearRegex = new Regex(monthOfYearPattern);

            this.timeMC = timeRegex.Matches(tempInputTxt);
            this.dateMC = dateRegex.Matches(tempInputTxt);
            this.timeOfDayMC = timeOfDayRegex.Matches(tempInputTxt);
            this.dayTimeIndexMC = dayTimeIndexRegex.Matches(tempInputTxt);
            this.dayOfWeekMC = dayOfWeekRegex.Matches(tempInputTxt);
            this.weekTimeIndexMC = weekTimeIndexRegex.Matches(tempInputTxt);
            this.monthTimeIndexMC = monthTimeIndexRegex.Matches(tempInputTxt);
            this.monthOfYearMC = monthOfYearRegex.Matches(tempInputTxt);

            

            sendMCVal2TaskVal(timeMC, ref timeValue);
            //sendMCVal2TaskVal(dateMC, ref dateValue);
            sendMCVal2TaskVal(timeOfDayMC, ref timeOfDayValue);
            if (timeOfDayValue.Count() == 0) timeOfDayValue.Add("");
            sendMCVal2TaskVal(dayTimeIndexMC, ref dayTimeIndexValue);
            if (dayTimeIndexValue.Count() == 0) dayTimeIndexValue.Add("");
            sendMCVal2TaskVal(dayOfWeekMC, ref dayOfWeekValue);
            if (dayOfWeekValue.Count() == 0) dayOfWeekValue.Add("");
            sendMCVal2TaskVal(weekTimeIndexMC, ref weekTimeIndexValue);
            if (weekTimeIndexValue.Count() == 0) weekTimeIndexValue.Add("");
            sendMCVal2TaskVal(monthTimeIndexMC, ref monthTimeIndexValue);
            if (monthTimeIndexValue.Count() == 0) monthTimeIndexValue.Add("");
            sendMCVal2TaskVal(monthOfYearMC, ref monthOfYearValue);
            if (monthOfYearValue.Count() == 0) monthOfYearValue.Add("");

            for (int i = 0; i < timeValue.Count();i++ )
                foreach (String test2 in durationValue)
                {
                    if (test2.Contains(timeValue[i]))
                    {
                        timeValue.RemoveAt(i);
                        i--;
                    }
                }
            if (timeValue.Count() == 0) timeValue.Add("");
            //Dựa vào vị trí để loại bỏ những giá trị giờ - phút bị bắt nhầm trong DateValue. Ví dụ: 4h30 vấn bị bắt trong DateValue{4, 30}
            //Hai bộ MatchCollection sử dụng: timeMC và dateMC
            List<String> invalidDateVal = new List<String>();
            dateValue.Clear();
            for (int i = 0; i < dateMC.Count; i++)
            {
                //với mỗi giá trị DateMC[i] duyệt xem nó có nằm gọn trong timeMC[j] không. Nếu có thì không add
                //tính số khoảng trắng bắt đầu của DateMC[i]
                int numSpaceDateMC = 0;
                for (int k = 0; k < dateMC[i].Value.Length; k++)
                {
                    if (dateMC[i].Value[k].Equals(' '))
                    {
                        numSpaceDateMC++;
                    }
                    else
                    {
                        break;
                    }
                }
                Boolean isInsideTime = false;
                for (int j = 0; j < timeMC.Count; j++)
                {
                    //tính số khoảng trắng bắt đầu của timeMC[i]
                    int numSpaceTimeMC = 0;
                    for (int n = 0; n < timeMC[j].Value.Length; n++)
                    {
                        if (timeMC[j].Value[n].Equals(' '))
                        {
                            numSpaceTimeMC++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if ((dateMC[i].Index + numSpaceDateMC >= timeMC[j].Index + numSpaceTimeMC) && (dateMC[i].Index + numSpaceDateMC + dateMC[i].Value.Trim().Length <= timeMC[j].Index + numSpaceTimeMC + timeMC[j].Value.Trim().Length))
                    {
                        // Trường hợp vi phạm: vị trí dateMC[j] chứa trong timeMC[i]
                        isInsideTime = true;
                        break;
                    }
                    
                }
                if (!isInsideTime)
                {
                    dateValue.Add(dateMC[i].Value.Trim());
                }
            }
            if (dateValue.Count == 0) dateValue.Add("");

            // Xử lý Deadline & Duration giao nhau: ví dụ: trc 18/11 -30p -> 18/11 - 30 và 30p
            if (deadlineMC.Count == 1 && durationMC.Count == 1)
            {
                if (deadlineMC[0].Index < durationMC[0].Index && deadlineMC[0].Index + deadlineMC[0].Value.Trim().Length > durationMC[0].Index)
                {
                    deadlineValue[0] = deadlineValue[0].Substring(0, durationMC[0].Index - deadlineMC[0].Index);
                }
            }

            //loại bỏ phần bắt dư gồm các con số có 2 chữ số trở xuống ^^
            //for (int i = 0; i < dateValue.Count(); i++)
            //{
            //    if (dateValue[i].Length <= 2)
            //    {
            //        dateValue.RemoveAt(i);
            //        i--;
            //    }
            //}

            if (dateValue.Count() == 0) dateValue.Add("");

            if (deadlineValue.Count() != 0)
            {
                foreach (String temp in deadlineValue)
                {
                    foreach (String tempKW in deadlineKeyword)
                    {
                        if(temp.Contains(tempKW))
                        {
                            catchedValue.Add(tempKW);
                        }
                    }
                }

                tempInput += "trước " + timeValue[0] + " "
                    + timeOfDayValue[0] + " "
                    + dayTimeIndexValue[0] + " "
                    + dayOfWeekValue[0] + " "
                    + weekTimeIndexValue[0] + " "
                    + monthTimeIndexValue[0] + " "
                    + monthOfYearValue[0] + " "
                    + dateValue[0] + " ";
                this.deadlineMC = deadlineRegex.Matches(tempInput);
            }
            else
            {
                tempInput += "lúc " + timeValue[0] + " "
                    + timeOfDayValue[0] + " "
                    + dayTimeIndexValue[0] + " "
                    + dayOfWeekValue[0] + " "
                    + weekTimeIndexValue[0] + " "
                    + monthTimeIndexValue[0] + " "
                    + monthOfYearValue[0] + " "
                    + dateValue[0] + " ";
                this.eventStartMC = eventStartRegex.Matches(tempInput);
            }
            
                     
            if (deadlineMC.Count == 0)
            {
                //có thể là Appointment vì appointment ko chứa deadline keyword.

                if (eventStartMC.Count > 0)
                {
                    isTask = false;
                    sendMCVal2TaskVal(eventStartMC, ref deadlineValue);
                    heuristicEnhancement();
                }
            }
            else
            {

                sendMCVal2TaskVal(deadlineMC, ref deadlineValue);
                heuristicEnhancement();
            }

            sendMCVal2TaskVal(durationMC, ref durationValue);
            heuristicEnhancement();

            sendMCVal2TaskVal(priorityMC, ref priorityValue);
            heuristicEnhancement();
            sendMCVal2TaskVal(minsplitMC, ref minsplitValue);
            if (durationMC.Count == 0)
            {
                _taskInputTxt += " khoảng 0h";
                _originalInputTxt += " khoảng 0h";

                durationValue.Add(" khoảng 0h");
            }
            if (deadlineMC.Count == 0 && isTask)
            {
                _taskInputTxt += " trước 31/12/9999 11:59:59 PMh";
                _originalInputTxt += " trước 31/12/9999 11:59:59 PMh";

                deadlineValue.Add(" trước 31/12/9999 11:59:59 PMh");
            }
            if (priorityMC.Count == 0)
            {
                _taskInputTxt += " bình thường";
                _originalInputTxt += " bình thường";

                priorityValue.Add(" bình thường");
            }
            
        }

        private void buildCatchedValues()
        {

            catchedValue.Add(timeValue[0]);
            catchedValue.Add(timeOfDayValue[0]);
            catchedValue.Add(dayTimeIndexValue[0]);
            catchedValue.Add(dayOfWeekValue[0]);
            catchedValue.Add(weekTimeIndexValue[0]);
            catchedValue.Add(monthTimeIndexValue[0]);
            catchedValue.Add(monthOfYearValue[0]);
            catchedValue.Add(dateValue[0]);

            catchedValue.Add(durationValue[0]);
            catchedValue.Add(priorityValue[0]);
            if (minsplitValue.Count != 0)
            {
                catchedValue.Add(minsplitValue[0]);
            }
        }

        private void buildKeywordPosition(String durationValue, String deadlineValue, String priorityValue, String text)
        {
            keyWordPosition.Add(text.IndexOf(durationValue));
            keyWordPosition.Add(text.IndexOf(deadlineValue));
            keyWordPosition.Add(text.IndexOf(priorityValue));
            keyWordPosition.Sort(delegate(int s1, int s2)
            {
                return s1.CompareTo(s2);
            });
        }

        /// <summary>
        /// từ tập MC chuyển thành tập value của task để TIẾN Parse lấy value
        /// </summary>
        /// <param name="mc"></param>
        /// <param name="taskProposeValue"></param>
        private void sendMCVal2TaskVal(MatchCollection mc, ref List<String> taskProposeValue)
        {
            if (mc != null)
            {
                if (mc.Count > 0)
                {
                    taskProposeValue.Clear();
                    for (int i = 0; i < mc.Count; i++)
                    {
                        if (mc[i].Value.Trim() != "")
                        {
                            taskProposeValue.Add(mc[i].Value.Trim());
                        }
                    }
                }
                else
                {
                    taskProposeValue = new List<string>();
                }

            }
            else
            {
                taskProposeValue = new List<string>();
            }
        }

        /// <summary>
        /// Lấy tên của task dựa vào vị trí các keywords: duration, deadline, priority
        /// @Author: Tien & Thanh Long
        /// </summary>
        /// <param name="keyWordPosition"></param>
        /// <returns></returns>
        private String parseTaskName(List<int> keyWordPosition, String TaskText)
        {
            int position = 0;
            int length = keyWordPosition[0];
            if (length == 0)
                length = keyWordPosition[1];
            for (int i = 1; i < keyWordPosition.Count - 1; i++)
            {
                if ((keyWordPosition[i + 1] - keyWordPosition[i]) > length)
                {
                    position = i;
                    length = keyWordPosition[i + 1] - keyWordPosition[i];
                }
            }
            String TaskName = TaskText.Substring(keyWordPosition[position], length + 1);
            Regex delDuration = new Regex(durationPattern);
            Match temp = delDuration.Match(TaskName);
            if (temp.Success)
            {
                TaskName = TaskName.Replace(temp.Value, "");
            }
            Regex delDeadline = new Regex(deadlinePattern);
            temp = delDeadline.Match(TaskName);
            if (temp.Success)
            {
                TaskName = TaskName.Replace(temp.Value, "");
            }
            Regex delDayofTime = new Regex(timeOfDayPattern);
            temp = delDayofTime.Match(TaskName);
            if (temp.Success)
            {
                TaskName = TaskName.Replace(temp.Value, "");
            }
            TaskName = TaskName.Trim();
            TaskName = TaskName.Substring(1, TaskName.Length - 1);
            if (TaskName[0] == '-') TaskName = TaskName.Substring(1, TaskName.Length - 1);
            if (TaskName[TaskName.Length - 1] == '-') TaskName = TaskName.Substring(0, TaskName.Length - 1);
            return TaskName.Trim();
        }

        /// <summary>
        /// Parse Task Name dựa trên các đoạn dữ liệu: deadline, duration, priority
        /// @Author: Thanh Long
        /// </summary>
        /// <param name="durationValue"></param>
        /// <param name="deadlineValue"></param>
        /// <param name="priorityValue"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        private String parseTaskName()
        {
            String tempText = this._taskInputTxt;

            buildCatchedValues();
            foreach (String temp in catchedValue)
            {
                if (temp != "")
                {
                    tempText = tempText.Replace(temp, SPLITCHARACTER);
                }
            }

            Regex splitWord = new Regex(SPLITCHARACTER);
            String[] words = splitWord.Split(tempText);
            int max = words[0].Length;
            int position = 0;
            for (int i = 1; i < words.Count(); i++)
            {
                if (max < words[i].Length)
                {
                    max = words[i].Length;
                    position = i;
                }
            }
            words[position] = words[position].Trim();
            if ((words[position][0] == '-') || (words[position][0] == ',')
                || (words[position][0] == '.') || (words[position][0] == '!') || (words[position][0] == '?'))
            {
                words[position] = words[position].Substring(1, words[position].Length - 1);
            }
            if (words[position][words[position].Length - 1] == '-')
            {
                words[position] = words[position].Substring(0, words[position].Length - 1);
            }


            String taskName = (words[position]).Trim();

            if (_originalInputTxt.ToLower().Contains(taskName))
            {
                int start = 0;
                int end = 0;
                for (int i = 0; i < _originalInputTxt.Length; i++)
                {
                    start = i;
                    if (_originalInputTxt.ToLower()[i] == taskName[0])//có thể đây là start
                    {
                        // tìm tiếp end
                        int j = 0;
                        for (j = 0; j < taskName.Length; j++)
                        {
                            if (_originalInputTxt.ToLower()[j + i] != taskName[j])
                            {// Nếu những chứ sau không đúng thì break vòng for này và tiếp tục tăng i lên
                                break;
                            }
                        }
                        if (j == taskName.Length)
                        {
                            // trường hợp chạy hết TaskName mà không bị break -> đây chính là taskName rồi->break
                            end = start + taskName.Length;
                            break;
                        }

                    }
                }
                if (end > start)
                {
                    taskName = _originalInputTxt.Substring(start, taskName.Length);
                }
            }

            while(taskName.Contains("  "))
            {
                taskName = taskName.Replace("  ", " ");
            }
            return taskName.Trim();
        }

        private Double calculateFraction(String fraction)
        {
            Double result = 0;
            String tempText = fraction;
            tempText = tempText.Replace("/", SPLITCHARACTER);

            Regex tempNumRegex = new Regex(SPLITCHARACTER);
            String[] tempNum = tempNumRegex.Split(tempText);

            result = Convert.ToDouble(tempNum[0]);
            for (int i = 1; i < tempNum.Count(); i++)
            {
                result /= Convert.ToDouble(tempNum[i]);
            }
            return result;
        }

        /// <summary>
        /// Nhận diện giá trị của Duration String và trả về số phút chứa trong đó
        /// </summary>
        /// <param name="durationStr"></param>
        /// <returns>Số phút nằm trong durationStr</returns>
        private int parseDurationValue(String durationStr)
        {
            int durationValue = 0;

            //Chuyển giá trị giờ

            int _hourValue = 0;
            String tempString = @"((\d+/\d+)|(\d+(\.\d+)?))" + @"\s*" + hourPattern;
            Regex hourRex = new Regex(tempString);
            Match hour = hourRex.Match(durationStr);
            String temphour = hour.Value;
            String hourValuePattern = @"((\d+/\d+)|(\d+(\.\d+)?))";
            Regex hourValueRex = new Regex(hourValuePattern);
            Match hourValue = hourValueRex.Match(temphour);


            if (hourValue.Success)
            {
                if (hourValue.Value.Contains('/'))
                {
                    _hourValue = (Int32)(calculateFraction(hourValue.Value) * 60);
                }
                else
                {
                    _hourValue = (Int32)(Convert.ToDouble(hourValue.Value) * 60);
                }
            }

            durationValue += _hourValue;


            //Chuyển giá trị phút
            int _minuteValue = 0;
            tempString = @"((\d+/\d+)|(\d+(\.\d+)?))" + @"\s*" + minutePattern;
            Regex minuteRex = new Regex(tempString);
            Match minute = minuteRex.Match(durationStr);
            String tempminute = minute.Value;
            String minuteValuePattern = @"((\d+/\d+)|(\d+(\.\d+)?))";
            Regex minuteValueRex = new Regex(minuteValuePattern);
            Match minuteValue = minuteValueRex.Match(tempminute);
            if (minuteValue.Success)
            {
                if (minuteValue.Value.Contains('/'))
                {
                    _minuteValue = (Int32)(calculateFraction(minuteValue.Value));
                }
                else
                {
                    _minuteValue = (Int32)(Convert.ToDouble(minuteValue.Value));
                }
            }

            durationValue += _minuteValue;

            //còn một số định dạng khác như tuần, ngày ...... thì cần gặp thống nhất định dạng ^^
            return durationValue;
        }

        /// <summary>
        /// validate datetime value
        /// </summary>
        /// <param name="ngay thang nam"></param>
        /// <returns>   0: valid
        ///             1: invalid day
        ///             2: invalid month
        ///             3: invalid year
        /// </returns>
        private int validateDatetimeValue(int day, int month, int year)
        {
            switch (month)
            {
                case 1:
                case 3:
                case 5:
                case 7:
                case 8:
                case 10:
                case 12:
                    if (day < 1 || day > 31)
                        return 1;
                    break;
                case 4:
                case 6:
                case 9:
                case 11:
                    if (day < 1 || day > 30)
                        return 1;
                    break;
                case 2:
                    if ((year % 100) % 4 == 0) //nam nhuan
                    {
                        if (day < 1 || day > 29)
                            return 1;
                    }
                    else if (day < 1 || day > 28)
                    {
                        return 1;
                    }
                    break;
                default:
                    return 2;
            }
            //if (year < DateTime.Now.Year)
            //return 3;
            return 0;
        }
        /// <summary>
        /// Lấy index của ngày của tuần. ví dụ: thứ 2 = 2; thứ 3 = 3
        /// </summary>
        /// <param name="dow"></param>
        /// <returns></returns>
        private int getDayOfWeekValue(DayOfWeek dow)
        {
            switch (dow)
            {
                case DayOfWeek.Monday:
                    return 2;
                case DayOfWeek.Tuesday:
                    return 3;
                case DayOfWeek.Wednesday:
                    return 4;
                case DayOfWeek.Thursday:
                    return 5;
                case DayOfWeek.Friday:
                    return 6;
                case DayOfWeek.Saturday:
                    return 7;
                case DayOfWeek.Sunday:
                    return 8;
                default:
                    return 2;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="deadlineStr"></param>
        /// <returns></returns>
        private DateTime parseDeadlineValue(String deadlineStr)
        {
            int _hourValue = DateTime.MinValue.Hour;
            //Chuyển giá trị giờ

            String tempString = @"\d{1,2}" + @"\s*" + hourPattern;
            Regex hourRex = new Regex(tempString);
            Match hour = hourRex.Match(deadlineStr);

            String temphour = hour.Value;
            //xóa giờ để khỏi nhầm lẫn

            String hourValuePattern = @"\d{1,2}";
            Regex hourValueRex = new Regex(hourValuePattern);
            Match hourValue = hourValueRex.Match(temphour);

            if (hourValue.Success)
            {
                _hourValue = Convert.ToInt32(hourValue.Value);
                //deadlineStr = deadlineStr.Replace(hourValue.Value, "");
            }


            int intHour = _hourValue;
            String checkTimeofDay = "chiều|chieu|tối|toi|PM|pm";
            Regex TimeofDayRegex = new Regex(checkTimeofDay);
            Match TimeofDay = TimeofDayRegex.Match(deadlineStr);
            if (TimeofDay.Success && hourValue.Success)
            {
                if (intHour < 12) intHour += 12;
                //deadlineStr = deadlineStr.Replace(TimeofDay.Value, "");
            }

            //Chuyển giá trị phút
            // cuối cùng: 3:00:12 hoặc 4h 14/10 hoặc 3h30 14/10 3h30' -> có đơn vị hoặc là khoảng trắng sau đó
            tempString = @"\s*" + @"\d{1,2}" + @"\s*" + hourPattern + @"\s*" + @"(?<minuteVall>(\d{1,2}))" + @"\s*" + "((" + minutePattern + @")|(\s+))";
            Regex minuteRex = new Regex(tempString);
            Match minute = minuteRex.Match(deadlineStr);
            String tempminute = minute.Value;
            String minuteValuePattern = @"\d{1,2}";
            Regex minuteValueRex = new Regex(minuteValuePattern);
            Match minuteValue = minuteValueRex.Match(tempminute);

            //int intMinute = DateTime.MaxValue.Minute;
            int intMinute = 0;


            if (minute.Groups["minuteVall"].Success)
            {
                intMinute = Convert.ToInt32(minute.Groups["minuteVall"].Value);
            }


            //int intSecond = DateTime.MaxValue.Second;
            int intSecond = 0;

            //Remove những dữ liệu không cần thiết để tránh gây nhầm lẫn:
            if (hourValue.Success)
            {
                deadlineStr = deadlineStr.Replace(hourValue.Value, "");
                if (TimeofDay.Success)
                {
                    deadlineStr = deadlineStr.Replace(TimeofDay.Value, "");
                }
            }

            if (minute.Groups["minuteVall"].Success)
            {
                deadlineStr = deadlineStr.Replace(minute.Groups["minuteVall"].Value, "");
            }

            int intYear = DateTime.MaxValue.Year;
            int intMonth = DateTime.MaxValue.Month;
            //int intDay = DateTime.MaxValue.Day;
            int intDay = 1;
            if (hourValue.Success || minute.Groups["minuteVall"].Success)
            {
                intYear = DateTime.Now.Year;
                intMonth = DateTime.Now.Month;
                //int intDay = DateTime.MaxValue.Day;
                intDay = DateTime.Now.Day;
            }
            if (deadlineMC.Count > 0 || !isTask)
            {
                Match dlm;
                if (isTask)
                {
                    dlm = deadlineMC[selectedDeadlineMC];
                }
                else
                {
                    dlm = eventStartMC[selectedEventStartMC];
                }
                //Chú ý: nếu nhập: trước thứ bảy tuần sau tháng kia. thì chương trình sẽ nhận trước thứ bảy tuần sau, không nhận tháng kia
                if (dlm.Groups["daytimeIndex"].Success ||
                    dlm.Groups["dayOfWeek"].Success ||
                    dlm.Groups["weektimeIndex"].Success ||
                    dlm.Groups["monthtimeIndex"].Success ||
                    dlm.Groups["monthOfYear"].Success)
                {
                    DateTime test = DateTime.Now.Date;
                    // Trường hợp rơi vào những dạng: ngày mai, tháng tới, tuần tới... => một khi đã chọn tháng sau thì ko xét thêm: tháng 11 2011
                    Boolean hasMonthTimeIndex = false;
                    if (dlm.Groups["monthtimeIndex"].Success)
                    {
                        // trường hợp: tháng kế, tháng tới
                        // cộng thêm một đơn vị vào tháng     
                        hasMonthTimeIndex = true;
                        double monthAskew = this.monthtimeIndexNV.getValue(dlm.Groups["monthtimeIndex"].Value.Trim());
                        test = test.AddMonths((int)monthAskew);
                        test = test.AddDays(-DateTime.Now.Day + 1);
                        // xử lý trường hợp: ngày 22 tháng sau

                        if (dlm.Groups["dayInMonth"].Success)
                        {

                            int dateNum = int.Parse(dlm.Groups["dayInMonth"].Value.Trim());
                            try
                            {
                                test = new DateTime(test.Year, test.Month, dateNum, 0, 0, 0);
                            }
                            catch (Exception ex)
                            {
                                test = DateTime.Now;
                            }
                        }
                    }

                    if (dlm.Groups["monthOfYear"].Success && !hasMonthTimeIndex)
                    {
                        intMonth = (int)monthOfYearNV.getValue(dlm.Groups["monthOfYear"].Value);

                        if (dlm.Groups["dayInMonthOfYear"].Success)
                        {
                            if (dlm.Groups["dayInMonthOfYear"].Value.Trim().Length < 3)
                            {//Tránh việc bắt nhầm năm, vì ngày chỉ có từ 1 đến 2 số
                                intDay = int.Parse(dlm.Groups["dayInMonthOfYear"].Value.Trim());
                            }
                        }
                        if (dlm.Groups["dayInMonthOfYearL"].Success)
                        {
                            if (dlm.Groups["dayInMonthOfYearL"].Value.Trim().Length < 3)
                            {//Tránh việc bắt nhầm năm, vì ngày chỉ có từ 1 đến 2 số
                                intDay = int.Parse(dlm.Groups["dayInMonthOfYearL"].Value.Trim());
                            }
                        }

                        // check xem sau đó có năm nữa không. ví dụ: dec 2012
                        Regex yearRegex = new Regex(@"\d{4}");
                        Match yearMatch = yearRegex.Match(deadlineStr.Trim());
                        if (yearMatch.Success)
                        {
                            intYear = int.Parse(yearMatch.Value);
                        }
                        else
                        {
                            intYear = DateTime.Now.Year;
                        }
                        try
                        {
                            test = (intDay == 1 || intDay > 31) ? new DateTime(intYear, intMonth, 1, 0, 0, 0) : new DateTime(intYear, intMonth, intDay, 0, 0, 0);
                        }
                        catch (Exception ex)
                        {
                            test = DateTime.MaxValue;
                            //throw;
                        }
                    }

                    Boolean isDayOfWeekGroupProcessed = false;
                    double numOfAddDays = 0;
                    if (dlm.Groups["weektimeIndex"].Success)
                    {
                        // trường hợp: tuần tới, tuần kế
                        //reset về đầu tuần, cộng thêm 7 ngày nữa.
                        double weekIndex = weektimeIndexNV.getValue(dlm.Groups["weektimeIndex"].Value.Trim());
                        int currentDayOfWeek = getDayOfWeekValue(DateTime.Now.DayOfWeek);
                        numOfAddDays = weekIndex * 7 - (currentDayOfWeek - 2);
                        test = DateTime.Now.Date.AddDays(numOfAddDays);
                        if (dlm.Groups["dayOfWeek"].Success)
                        {
                            // trường hợp vừa có thứ, vừa có tuần (giải pháp Thanh Long)
                            isDayOfWeekGroupProcessed = true;
                            numOfAddDays = (dayOfWeekNV.getValue(dlm.Groups["dayOfWeek"].Value.Trim()) - 2);
                            test = test.AddDays(numOfAddDays);
                            if (!hourValue.Success)
                            {
                                if (deadlineStr.Contains("sáng") || deadlineStr.Contains("sang") || deadlineStr.Contains("morning"))
                                {
                                    test = test.AddHours(6);
                                    intHour = test.Hour;
                                }
                                else if (deadlineStr.Contains("trưa") || deadlineStr.Contains("trua") || deadlineStr.Contains("afternoon") || deadlineStr.Contains("noon"))
                                {
                                    test = test.AddHours(12);
                                    intHour = test.Hour;
                                }
                                else if (deadlineStr.Contains("chiều"))
                                {
                                    test = test.AddHours(15);
                                    intHour = test.Hour;
                                }
                                else if (deadlineStr.Contains("tối") || deadlineStr.Contains("toi") || deadlineStr.Contains("evening"))
                                {
                                    test = test.AddHours(18);
                                    intHour = test.Hour;
                                }
                                else if (deadlineStr.Contains("night"))
                                {
                                    test = test.AddHours(20);
                                    intHour = test.Hour;
                                }
                                else if (deadlineStr.Contains("midnight") || deadlineStr.Contains("nửa đêm"))
                                {
                                    test = test.AddHours(24);
                                    intHour = test.Hour;
                                }
                            }

                        }
                        //Nếu như thêm ngày mà bị tràn sang tháng sau thì thêm tháng.

                    }

                    if (dlm.Groups["dayOfWeek"].Success && !isDayOfWeekGroupProcessed)
                    {
                        // trường hợp có ngày trong tuần. Chỉnh ngày: (parsed < now)? thứ của tuần sau : parsed
                        int currentDayOfWeek = getDayOfWeekValue(DateTime.Now.DayOfWeek);
                        numOfAddDays = (dayOfWeekNV.getValue(dlm.Groups["dayOfWeek"].Value.Trim()) - currentDayOfWeek);
                        
                        test = DateTime.Now.Date.AddDays(numOfAddDays);
                        if (!hourValue.Success)
                        {
                            if (deadlineStr.Contains("sáng") || deadlineStr.Contains("sang") || deadlineStr.Contains("morning"))
                            {
                                test = test.AddHours(6);
                            }
                            else if (deadlineStr.Contains("trưa") || deadlineStr.Contains("trua") || deadlineStr.Contains("afternoon") || deadlineStr.Contains("noon"))
                            {
                                test = test.AddHours(12);
                            }
                            else if (deadlineStr.Contains("tối") || deadlineStr.Contains("toi") || deadlineStr.Contains("evening"))
                            {
                                test = test.AddHours(18);
                            }
                            else if (deadlineStr.Contains("night"))
                            {
                                test = test.AddHours(20);
                            }
                            else if (deadlineStr.Contains("midnight") || deadlineStr.Contains("nửa đêm"))
                            {
                                test = test.AddHours(24);
                            }
                            intHour = test.Hour;
                        }
                    }



                    //đã xử lý trường hợp Group: trước thứ hai tuần sau thì không cần xử lý trường hợp trước thứ hai lại làm gì cả.
                    if (dlm.Groups["daytimeIndex"].Success)
                    {
                        // Datetime.Now.Date + thêm vào ngày tương ứng.
                        if (dlm.Groups["moment"].Success && hourValue.Success)
                        {
                            test = DateTime.Now.Date.AddDays(daytimeIndexNV.getValue(dlm.Groups["daytimeIndex"].Value.Trim()));
                        }
                        else
                        {
                            string findDayTimeIndex = dlm.Groups["daytimeIndex"].Value;
                            if (dlm.Groups["moment"].Success)
                            {
                                findDayTimeIndex = (findDayTimeIndex.Contains(dlm.Groups["moment"].Value)) ? findDayTimeIndex : dlm.Groups["moment"].Value + " " + findDayTimeIndex;
                            }
                            test = DateTime.Now.Date.AddDays(daytimeIndexNV.getValue(findDayTimeIndex));
                            intHour = test.Hour;
                            intMinute = test.Minute;
                        }

                    }
                    intDay = test.Day;
                    intMonth = test.Month;
                    intYear = test.Year;
                }
                else
                {
                    // parse datevalue
                    String datePattern = @"(\s*(ngày|ngay)?\s*\d{1,2}\s*(tháng|thang|/|\\|-)\s*\d{1,2}\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2}))|(\s*(tháng|thang|/|\\|-)?\s*\d{1,2}\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2}))|(\s*(ngày|ngay)?\s*\d{1,2}\s*(tháng|thang|/|\\|-)\s*\d{1,2}\s*)|(\s*(ngày|ngay)?\s*\d{1,2}\s*)|(\s*(tháng|thang|/|\\|-)\s*\d{1,2}\s*)|(\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2})|(\d{4}))";
                    Regex dateRegex = new Regex(datePattern);
                    Match date = dateRegex.Match(deadlineStr);
                    if (date.Success)
                    {
                        String tempPattern = @"(\d+)";
                        Regex numberRegex = new Regex(tempPattern);

                        MatchCollection tempNumber = numberRegex.Matches(date.Value);
                        List<int> number = new List<int>();
                        foreach (Match temp in tempNumber)
                        {
                            number.Add(Convert.ToInt32(temp.Value));
                        }

                        switch (number.Count())
                        {
                            case 3:
                                intYear = Convert.ToInt32(number[2]);
                                intMonth = Convert.ToInt32(number[1]);
                                intDay = Convert.ToInt32(number[0]);
                                break;
                            case 2:
                                if (number[1] > 12)
                                {
                                    intYear = Convert.ToInt32(number[1]);
                                    intMonth = Convert.ToInt32(number[0]);
                                }
                                else
                                {
                                    intMonth = Convert.ToInt32(number[1]);
                                    intDay = Convert.ToInt32(number[0]);
                                    intYear = DateTime.Now.Year;
                                }
                                break;
                            case 1:
                                if (number[0] / 100 > 0)
                                {
                                    intYear = Convert.ToInt32(number[0]);
                                    intDay = 1;
                                    intMonth = 1;
                                    intHour = 0;
                                    intMinute = 0;
                                    intSecond = 0;
                                }
                                else if (number[0] > 12)
                                {
                                    intDay = Convert.ToInt32(number[0]);
                                    intYear = DateTime.Now.Year;
                                    intMonth = DateTime.Now.Month;
                                    //intHour = 0;
                                    //intMinute = 0;
                                    //intSecond = 0;
                                }
                                else if (deadlineStr.Contains("ngày") || deadlineStr.Contains("ngay"))
                                {
                                    intMonth = DateTime.Now.Month;
                                    intYear = DateTime.Now.Year;
                                    intDay = number[0];
                                }
                                else
                                {
                                    intMonth = Convert.ToInt32(number[0]);
                                    intYear = DateTime.Now.Year;
                                    intDay = 1;
                                    //intHour = 0;
                                    //intMinute = 0;
                                    //intSecond = 0;
                                }
                                break;
                            default:
                                if (hourValue.Success || minuteValue.Success)
                                {
                                    DateTime Deadline = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, intHour, intMinute, 0);
                                    return Deadline;
                                }
                                else
                                    return DateTime.MaxValue;
                        }
                    }
                    else
                    {
                        //Kiểm tra TimeOfDate: ví dụ: trưa mai, trưa mốt...
                        //Chú ý không thể có vụ: trước trưa mai tuần sau hay trước trưa mai năm sau.
                        Regex specialTimeOfDateRegex = new Regex(this.daytimeIndexPattern);
                        Match specialTimeOfDateMatch = specialTimeOfDateRegex.Match(deadlineStr);
                        if (specialTimeOfDateMatch.Success)
                        {
                            DateTime test = DateTime.Now.Date.AddDays(daytimeIndexNV.getValue(specialTimeOfDateMatch.Value.Trim()));
                            intYear = test.Year;
                            intMonth = test.Month;
                            intDay = test.Day;
                            intHour = test.Hour;
                            intMinute = test.Minute;
                            intSecond = test.Second;
                        }
                    }
                    if (intYear == 0)
                    {
                        intYear = DateTime.Now.Year;
                    }
                    else if (intYear < 100)
                    {
                        intYear += 2000;
                    }
                    if (intMonth == 0 || intMonth > 12)
                    {
                        intMonth = DateTime.Now.Month;
                    }
                    if (intDay == 0 || intDay > 31)
                    {
                        intDay = DateTime.Now.Day;
                    }

                    switch (validateDatetimeValue(intDay, intMonth, intYear))
                    {
                        case 1:
                        case 2:
                        case 3:
                            return DateTime.MaxValue;
                    }
                }
            }
            DateTime deadline;
            try
            {
                deadline = new DateTime(intYear, intMonth, intDay, intHour, intMinute, intSecond);
            }
            catch (Exception ex)
            {
                deadline = DateTime.Now.Date;
            }
            //if (deadline < DateTime.Now)
            //return DateTime.Now.Date;

            return deadline;

        }

        private void parseDeadlineValue()
        {

            //    //Chuyển giá trị giờ

            //    String tempString = @"\d{1,2}" + @"\s*" + hourPattern;
            //    Regex hourRex = new Regex(tempString);
            //    Match hour = hourRex.Match(deadlineStr);
            //    String temphour = hour.Value;
            //    String hourValuePattern = @"\d{1,2}";
            //    Regex hourValueRex = new Regex(hourValuePattern);
            //    Match hourValue = hourValueRex.Match(temphour);

            //    int _hourValue = DateTime.Now.Hour;
            //    if (hourValue.Success)
            //    {
            //        _hourValue = Convert.ToInt32(hourValue.Value);
            //    }

            //    int intHour = _hourValue;
            //    String checkTimeofDay = "chiều|chieu|tối|toi|PM|pm";
            //    Regex TimeofDayRegex = new Regex(checkTimeofDay);
            //    Match TimeofDay = TimeofDayRegex.Match(deadlineStr);
            //    if (TimeofDay.Success)
            //    {
            //        if (intHour < 12) intHour += 12;
            //    }

            //    //Chuyển giá trị phút

            //    tempString = @"\d{1,2}" + @"\s*" + minutePattern;
            //    Regex minuteRex = new Regex(tempString);
            //    Match minute = minuteRex.Match(deadlineStr);
            //    String tempminute = minute.Value;
            //    String minuteValuePattern = @"\d{1,2}";
            //    Regex minuteValueRex = new Regex(minuteValuePattern);
            //    Match minuteValue = minuteValueRex.Match(tempminute);

            //    int _minuteValue = DateTime.Now.Minute;
            //    if (minuteValue.Success)
            //    {
            //        _minuteValue = Convert.ToInt32(minuteValue.Value);
            //    }

            //    //Chuyển giá trị năm
            //    //String yearPattern = "(" + @"(\\|/)" + @"(\d{4}|\d{2})" + @"(\s|$))|" + "((năm|nam)" + @"(\s*(\d{4}|\d{2}))" + ")";
            //    String yearPattern = @"(\s*(/|\\|-|năm|nam)\s*(\d{4}|\d{2}))";
            //    Regex yearRex = new Regex(yearPattern);
            //    Match year = yearRex.Match(deadlineStr);
            //    String tempyear = year.Value;
            //    String yearValuePattern = @"(\d{4}|\d{2})";
            //    Regex yearValueRex = new Regex(yearValuePattern);
            //    Match yearValue = yearValueRex.Match(tempyear);
            //    int intYear = DateTime.Now.Year;
            //    if (yearValue.Success) intYear = Convert.ToInt32(yearValue.Value);

            //    //Chuyển giá trị tháng
            //    //String monthPattern = "(" + @"(\\|/)" + @"\d{1,2}" + @"(\\|/))|" + "((thang|tháng)" + @"\s*\d{1,2}" + ")";
            //    String monthPattern = @"(\s*(tháng|thang|/|\\|-)\s*(\d{1,2})\s*)";
            //    Regex monthRex = new Regex(monthPattern);
            //    Match month = monthRex.Match(deadlineStr);
            //    String tempmonth = month.Value;
            //    String monthValuePattern = @"\d{1,2}";
            //    Regex monthValueRex = new Regex(monthValuePattern);
            //    Match monthValue = monthValueRex.Match(tempmonth);
            //    int intMonth = DateTime.Now.Month;
            //    if (monthValue.Success) intMonth = Convert.ToInt32(monthValue.Value);

            //    //Chuyển giá trị ngày
            //    //String dayPattern = "(" + @"\s*" + @"\d{1,2}" + @"(\\|/))|" + "((ngày|ngay)" + @"\s*\d{1,2}" + ")";
            //    String dayPattern = @"(\s*(ngày|ngay)?\s*(\d{1,2})\s*(tháng|thang|/|\\|-))";
            //    Regex dayRex = new Regex(dayPattern);
            //    Match day = dayRex.Match(deadlineStr);
            //    String tempday = day.Value;
            //    String dayValuePattern = @"\d{1,2}";
            //    Regex dayValueRex = new Regex(dayValuePattern);
            //    Match dayValue = hourValueRex.Match(tempday);
            //    int intDay = DateTime.Now.Day;
            //    if (dayValue.Success) intDay = Convert.ToInt32(dayValue.Value);

            //    DateTime Deadline = new DateTime(intYear, intMonth, intDay, intHour, _minuteValue, 0);

            //return Deadline;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="priorityStr"></param>
        /// <returns></returns>
        private double parsePriorityValue(String priorityStr)
        {
            double val = priorityNV.getValue(priorityStr.Trim());
            return (val > 0 && val <= 10) ? val : 5;
        }

        private int parseMinSplitValue()
        {
            int result = -1;
            if (minsplitMC.Count > 0)
            {
                if (minsplitMC[selectedMinsplitMC].Success)
                {
                    if (minsplitMC[selectedMinsplitMC].Groups["durationValue"].Success)//có minplit chứa duration
                    {
                        String minsplitVal = minsplitMC[selectedMinsplitMC].Groups["durationValue"].Value;
                        result = parseDurationValue(minsplitVal);
                    }
                    else
                    {
                        //không có duration mà vẫn có minsplit -> đây là trường hợp nosplit

                        return NO_SPLIT;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Chọn ra giá trị "hợp lý" nhất trong nhiều giá trị đọc được từ Regex
        /// </summary>
        protected override void heuristicEnhancement()
        {
            selectedDeadlineMC = 0;
            selectedDurationMC = 0;
            selectedPriorityMC = 0;

            #region process duration
            if (durationValue.Count > 1)
            {
                foreach (String tempDurationValue in durationValue)
                {
                    foreach (String tempDeadline in deadlineKeyword)
                    {
                        if (tempDurationValue.Contains(tempDeadline))
                        {
                            durationValue.Remove(tempDurationValue);
                            selectedDurationMC++;
                        }
                    }

                }

                for (int i = 0; i < durationValue.Count(); i++)
                {
                    int j = 0;
                    for (; j < durationKeyword.Count(); j++)
                    {
                        if (durationValue[i].Contains(":"))
                        {
                            durationValue.RemoveAt(i);
                            i--;
                            break;
                        }
                        if (durationValue[i].Contains(durationKeyword[j]) || durationValue[i].Contains("tieng") || durationValue[i].Contains("tiếng"))
                        {
                            break;
                        }
                    }
                    if (j >= durationKeyword.Count())
                    {
                        durationValue.RemoveAt(i);
                        i--;
                    }
                }
            }
            #endregion

            #region process deadline
            if (deadlineValue.Count > 1)
            {
                //Kiểm tra xem có deadline Value nào bất hợp lệ hay không (vì deadlineValue được dùng cho trường hợp eventStart nên có thể bị "bắt nhầm"
                for (int i = 0; i < deadlineValue.Count; i++)
                {
                    if (deadlineValue[i].Contains("tiếng") || deadlineValue.Contains("tieng"))
                    {
                        deadlineValue.RemoveAt(i);
                        i--;
                    }
                }
            }
            if (deadlineValue.Count() > 0 && durationValue.Count() > 0)
            {
                String tempText = _taskInputTxt;
                //vì deadline bắt buộc có keyword do đó không thể xảy ra trường hợp "bắt nhầm" 
                //deadline mà chỉ chỉ có thể xảy ra "bắt nhầm" duration
                for (int i = 0; i < deadlineValue.Count; i++)
                {
                    tempText = tempText.Replace(deadlineValue[i], "");
                }
                Regex durationRegex = new Regex(this.durationPattern);
                this.durationMC = durationRegex.Matches(tempText);
                sendMCVal2TaskVal(this.durationMC, ref durationValue);

            }
            #endregion

            constrainValue();
            constrainValueScope();
            constrainValueUnit();
            chooseBestValue();
        }
        #endregion

        #region Heuristic Enhancements Methods
        protected override void constrainValue()
        {

        }

        protected override void constrainValueScope()
        {
            //throw new NotImplementedException();
        }

        protected override void constrainValueUnit()
        {
            //throw new NotImplementedException();
        }

        protected override void chooseBestValue()
        {
            //throw new NotImplementedException();
        }
        #endregion

        #region Utils

        private void mapNameValue(ref NameValue result, List<String> name, double[] value)
        {
            if (name.Count == value.Length)
            {
                for (int i = 0; i < name.Count; i++)
                {
                    result.addToList(name[i], value[i]);
                }
            }
            else
            {
                throw new Exception();
            }
        }

        private List<int> getPositionFromText(String pattern, String text)
        {
            List<int> result = new List<int>();
            for (int i = 0; i < text.Count(); i++)
            {
                for (int j = 0, k = i; j < pattern.Count(); j++, k++)
                {
                    if (pattern[j] != text[k - 1])
                    {
                        break;
                    }
                    if (j == pattern.Count() - 1)
                    {
                        result.Add(i);
                        i = k;
                    }
                }
            }

            return result;
        }

        private void buildKeywordTable(List<String> pattern, String text, DataTable dtb)
        {
            //if (pattern == null || dtb == null)
            //{
            //    throw new Exception();
            //}
            //else
            //{
            //    List<int> temp = new List<int>();
            //    for (int i = 0; i < pattern.Count; i++)
            //    {
            //        temp = getPositionFromText(pattern[i], text);
            //        if (temp.Count > 0)
            //        {
            //            dtb.Rows.Add(i, temp, new List<String>());
            //        }
            //    }
            //}
        }
        /// <summary>
        /// Sinh ra Regex dạng lựa chọn. vd: (?<gioRegex>(gio|hour|h)\s*)
        /// Xây dựng phần thân + đuôi từ Regex đã có khai báo phần đầu dạng: "(?<tenRegEx>"
        /// Trước mỗi Regex này có thể là khoảng trắng hoặc không
        /// Sau khi build xong sẽ tự thêm phần "\s*)" còn thiếu.
        /// Chú ý: RegexDB sẽ được xếp thứ tự giảm dần về chiều dài
        /// </summary>
        /// <param name="pattern"></param>
        /// <param name="RegexDB"></param>
        private void buildRegexPattern(ref String pattern, List<String> RegexDB)
        {
            RegexDB.Sort(delegate(String s1, String s2)
            {
                return s2.Length.CompareTo(s1.Length);
            });
            pattern += @"\s*(";
            for (int i = 0; i < RegexDB.Count() - 1; i++)
            {
                pattern += RegexDB[i] + "|";
            }
            pattern += RegexDB[RegexDB.Count - 1];
            pattern += @")\s*";
            pattern += ")";
        }

        private String SplitWord(String pattern, String text)
        {
            pattern = @"\s+";
            return null;
        }

        #endregion

        #region Second_SNLP_Algorithm
        private void Init_SNLP()
        {
            Regex SNLP_Duration = new Regex("khoảng|trong");
            Regex SNLP_Deadline = new Regex("trước");


        }

        private void Recognise_Pattern(string _TaskInputText)
        {

        }

        private void Recognise_Value()
        {

        }

        private void Heuristic_Solving()
        {

        }



        #endregion

    }
}
